<?php
/**
 * 后台路服务 用户将所有路由导入权限表
 * User：liujun
 * Date：2022/3/5
 * Time：2:04 PM
 */

namespace Encore\Admin\Actions\Custom;

use Encore\Admin\Auth\Database\Permission;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Route;

class AdminRouteService
{
    use AutoMatchAdminMenuTrait;

    protected array $ignoreMethods = ['HEAD', 'PATCH'];
    protected array $ignoreTables = ['search', 'upload', 'permission_batch_set'];

    public Collection $routeLists;
    public Collection $tableRouteGroups;
    public array $insertData;

    /**
     * laravel admin 路由列表
     * 过滤无关内容，仅保留uri及methods
     */
    public function __construct()
    {
        $this->routeLists = collect(Route::getRoutes())
            ->filter(function ($route) {
                $middleware = data_get($route, 'action.middleware');
                if (!is_array($middleware)) {
                    $middleware = [$middleware];
                }
                return in_array('admin', $middleware);
            })->map(function ($route) {
                return [
                    'uri'     => $route->uri,
                    'methods' => $route->methods,
                ];
            });

        $this->toGroups();
        $this->toInsertData();
    }

    /**
     * 将路由按不同的关键模型名称（即表名)分组
     * 去除与auth相关的项
     */
    public function toGroups()
    {
        $methodsLists = [];
        $this->routeLists->each(function ($route) use (&$methodsLists) {
            foreach ($route['methods'] as $method) {
                if (!in_array($method, $this->ignoreMethods)) {
                    $uri = Str::replaceFirst(config('admin.route.prefix'), '', $route['uri']);
                    if ($uri && !Str::contains($uri, ['/auth', '_handle_', 'error'])) {
                        //数据库表名
                        $table = (string)Str::of($uri)
                            ->between('/', '/')
                            ->before('/')
                            ->replace('-', '_');

                        if (!in_array($table, $this->ignoreTables)) {
                            $methodsLists[] = [
                                'table_name'    => null,
                                'table'         => $table,
                                'uri'           => $uri,
                                'method'        => $method,
                                'admin_menu_id' => null,
                            ];
                        }
                    }
                }
            }
        });


        //auto match route's admin_menu_id
        $methodsLists = ($this->routesMatches($methodsLists));
        $this->tableRouteGroups = collect($methodsLists)->groupBy('table');
    }

    public function toInsertData()
    {
        $inserts = [];
        foreach ($this->tableRouteGroups->toArray() as $table => $routes) {
            foreach ($routes as $route) {
                //新增数据
                $uri = $route['uri'];
                $method = $route['method'];
                $table = $route['table'];
                $admin_menu_id = $route['admin_menu_id'];

                $bool = sprintf('/%s', Str::replace('_', '-', $table)) === $uri;
                $tableName = $route['table_name'] ?: $table;

                $path = Str::replace('_', '-', $table);
                //列表详情
                if ('GET' === $method && $bool) {
                    $inserts[] = [
                        'name'          => sprintf("查看%s", $tableName),
                        'slug'          => $table . '.view',
                        'http_method'   => ['GET'],
                        'http_path'     => $uri . '*',
                        'admin_menu_id' => $admin_menu_id,
                    ];
                }

                //新增数据
                if (Str::contains($uri, 'create')) {
                    $inserts[] = [
                        'name'          => sprintf("新增%s", $tableName),
                        'slug'          => $table . '.create',
                        'http_method'   => ['GET', 'POST'],
                        'admin_menu_id' => $admin_menu_id,
                        'http_path'     => collect([$uri . '*', sprintf('/%s', $path)])->join("\n")
                    ];
                }

                //编辑数据
                if (Str::contains($uri, 'edit')) {
                    $inserts[] = [
                        'name'          => sprintf("编辑%s", $tableName),
                        'slug'          => $table . '.edit',
                        'http_method'   => ['GET', 'PUT'],
                        'admin_menu_id' => $admin_menu_id,
                        'http_path'     => collect([sprintf('/%s/*/edit', $path), sprintf('/%s/*', $path)])->join("\n")
                    ];
                }

                //删除数据
                if ('DELETE' === $method) {
                    $inserts[] = [
                        'name'          => sprintf("删除%s", $tableName),
                        'slug'          => $table . '.delete',
                        'http_method'   => ['DELETE'],
                        'admin_menu_id' => $admin_menu_id,
                        'http_path'     => sprintf('/%s/*', $path)
                    ];
                }
            }
        }
        $this->insertData = $inserts;
    }

    /**
     * 导入数据
     * @return void
     */
    public function save()
    {
        //区分是更新还是新增
        $exists = Permission::query()->pluck('slug')->toArray();
        $inserts = [];
        foreach ($this->insertData as $insert) {
            $insert['http_method'] = join(',', $insert['http_method']);
            if (!in_array($insert['slug'], $exists)) {
                $insert['created_at'] = now();
                $insert['updated_at'] = now();
                $inserts[] = $insert;
            } else {
                if (isset($insert['admin_menu_id'])) {
                    Permission::query()->where('slug', $insert['slug'])->update($insert);
                }
            }
        }
        if ($inserts) {
            Permission::query()->insert($inserts);
        }
    }
}